
if SERVER then

function createEntityFunc(player, entityData)

	local entity = ents.Create( entityData.classname )
	if(entity and entity:IsValid()) then
		
		if entityData.model != "" then
		entity:SetModel(entityData.model)
		end
		entity:PhysicsInit(entityData.physicsInit)
		entity:SetMoveType(entityData.physicsMovetype)
		entity:SetPos(Vector(entityData.posX,entityData.posY,entityData.posZ))
		entity:Spawn()

		entity:SetNWBool("IsFreeze",false)			
		   
		local physicsObject = entity:GetPhysicsObject()
		if physicsObject and physicsObject:IsValid() then
			physicsObject:Wake()
		end
	end

end
datastream.Hook("CreateEntity", "CreateEntity", createEntityFunc);


function drawPlayerWeaponFunc(player, data)
	drawPlayerWeapon = data.Value
end
datastream.Hook("DrawPlayerWeapon", "DrawPlayerWeapon", drawPlayerWeaponFunc);


function createActorFunc(player, actorData)

	if actorData and actorData.classname then

		local entity = ents.Create( actorData.classname )

		//if actorData.classname == "dead" then
		//	entity = ents.Create( "prop_ragdoll" )
		//else
		//	
		//end

		if(entity and entity:IsValid()) then
			
			if actorData.modelname then
				entity:SetModel(actorData.modelname)
			end
			entity:PhysicsInit(SOLID_VPHYSICS)
			entity:SetMoveType(MOVETYPE_VPHYSICS)
			entity:SetPos(Vector(actorData.posX,actorData.posY,actorData.posZ))

	   		if actorData.classname != "prop_ragdoll" then
				if (actorData.equipment != "") then 
					print(actorData.equipment )
					entity:SetKeyValue("additionalequipment", actorData.equipment) 
				end
			end

			entity:Spawn()
			//Unique name important for animation sequence purposes
			if actorData.classname != "prop_ragdoll" then
				//print("CREATED:",string.format("MMActor%i", entity:EntIndex()))
				entity:SetName(string.format("MMActor%i", entity:EntIndex()))
			end
			local physicsObject = entity:GetPhysicsObject()
			if physicsObject and physicsObject:IsValid() then
				physicsObject:Wake()
			end
		end
	end
end
datastream.Hook("CreateActor", "CreateActor", createActorFunc);


function setCameraParametersFunc(player, cameraData)

	local entity = ents.GetByIndex(cameraData.entIndex)
	if entity and entity:IsValid() then
		entity:SetParameters(cameraData.parameters)
	end

end
datastream.Hook("SetCameraParameters", "SetCameraParameters", setCameraParametersFunc);

function setDualCameraParametersFunc(player, cameraData)

	local entityA = ents.GetByIndex(cameraData.entIndexA)
	local entityB = ents.GetByIndex(cameraData.entIndexB)
	if entityA and entityA:IsValid() and entityB and entityB:IsValid() then
		entityA:SetParameters(cameraData.parametersA)
		entityB:SetParameters(cameraData.parametersB)
	end

end
datastream.Hook("SetDualCameraParameters", "SetDualCameraParameters", setDualCameraParametersFunc);

function setToolStateFunc(player, toolStateData)
	if toolStateData then

		if player:GetWeapon("interaction") == nil then
			ply:Give("interaction")
		end

		local interactionTool = player:GetWeapon("interaction")
		if interactionTool then
			player:SelectWeapon("interaction")
			interactionTool:SetState(toolStateData.stateID)
		end
	end

end
datastream.Hook("SetToolState", "SetToolState", setToolStateFunc);

function ActorSequence_SetPlayStates(player, data)
	if data then
		for key, EntIndex in pairs(data.EntIndexes) do

			local sequenceEntity = ents.GetByIndex(EntIndex)
			sequenceEntity:SetPlayState(data.PlayState)

		end
	end
end
datastream.Hook("ActorSequence_SetPlayStates", "ActorSequence_SetPlayStates", ActorSequence_SetPlayStates);

function setCameraDataFunc(player, toolCameraData)
	if toolCameraData then

		if player:GetWeapon("interaction") == nil then
			ply:Give("interaction")
		end

		local interactionTool = player:GetWeapon("interaction")
		if interactionTool then
			player:SelectWeapon("interaction")
			interactionTool:SetTrackName(toolCameraData.trackID)
		end
	end

end
datastream.Hook("SetCameraData", "SetCameraData", setCameraDataFunc);

function ToggleFreezeFunc(player, entityData)

	local entity = ents.GetByIndex(entityData.entIndex)
	if (entity and entity:IsValid()) then

		local physicsObject = entity:GetPhysicsObject()
		if physicsObject and physicsObject:IsValid() then 

			if physicsObject:IsMoveable() then
				entity:SetNWBool("IsFreeze",true)			
				physicsObject:EnableMotion(false) 
				physicsObject:Sleep()
			else
				entity:SetNWBool("IsFreeze",false)			
				physicsObject:EnableMotion(true) 
				physicsObject:Wake()
				physicsObject:SetDamping(1,1)
			end
			
		end
	end
end
datastream.Hook("ToggleFreeze", "ToggleFreeze", ToggleFreezeFunc);

function deleteCameraFunc(player, eventData)

	local entity = ents.GetByIndex(eventData.entIndex)
	if (entity and entity:IsValid()) then
		entity:Delete()
	end
end
datastream.Hook("DeleteCamera", "DeleteCamera", deleteCameraFunc);

function deleteCameraTrackFunc(player, eventData)

	local entity = ents.GetByIndex(eventData.entIndex)
	if (entity and entity:IsValid()) then
		entity:DeleteTrack()
	end
end
datastream.Hook("DeleteCameraTrack", "DeleteCameraTrack", deleteCameraTrackFunc);

function removeSequenceActor(player, syncData)

	print("removeSequenceActor")
	if syncData != nil then
		print("syncData ok")
		local recipientEnt = ents.GetByIndex(syncData.recipientEntIdx)
		recipientEnt = recipientEnt.BaseClass.GetRootNode(recipientEnt)

		if recipientEnt and recipientEnt:IsValid() then
			print("recipientEnt ok")
			local removeEnt = ents.GetByIndex(syncData.removeEntIdx)
			local newActors = {}
			for _, actor in pairs(recipientEnt.OwnedActors) do 
			print("iterating")
				if actor != removeEnt then
					table.insert(newActors, actor)
				else
					print("found & excluded!")
				end
			end
			recipientEnt.Actors = newActors;
		end
	end
end
datastream.Hook("RemoveSequenceActor","RemoveSequenceActor", removeSequenceActor, nil);


/*************************************************
 * Recieves a message from the client which contains
 * a 'waypoint' and entity that should be an NPC
 * This causes the NPC to be inserted into the waypoint's
 * owned NPC list
 *************************************************/
function SetActorAssignWaypoint(player, data)

	if data != nil then
		
		local targetWaypoint = ents.GetByIndex(data.WaypointEntIndex)
		if targetWaypoint and targetWaypoint:IsValid() then
			
			local rootWaypoint = GetRootNode(targetWaypoint)			
			if rootWaypoint and rootWaypoint:IsValid() then

				//Set the tool to the correct state
				local stateData = {}
				stateData.stateID = STATE_GATHER_SEQUENCE_ACTORS
				setToolStateFunc(player, stateData)

				MODE_SEQUENCEGATHERACTORS.TargetWaypoint = rootWaypoint
			end
		else

			MODE_SEQUENCEGATHERACTORS.TargetWaypoint = nil;

		end
	end
end
datastream.Hook("SetActorAssignWaypoint","SetActorAssignWaypoint", SetActorAssignWaypoint, nil);


/*************************************************
 * Recieves a message from the client which contains
 * a 'camera' 
 * This causes sequences to be inserted into the cameras
 * sequence list
 *************************************************/
function SetSequenceAssignCamera(player, data)

	if data != nil then
		
		local targetCamerea = ents.GetByIndex(data.CameraEntIndex)
		if targetCamerea and targetCamerea:IsValid() then
			
	//		local rootCamera = GetRootNode(targetCamerea)			
	//		if rootCamera and rootCamera:IsValid() then

				//Set the tool to the correct state
				local stateData = {}
				stateData.stateID = STATE_GATHER_CAMERA_SEQUENCES
				setToolStateFunc(player, stateData)

				MODE_CAMERAGATHERSEQUENCE.TargetCamera = targetCamerea
		//	end
		else

			MODE_CAMERAGATHERSEQUENCE.TargetCamera = nil;

		end
	end
end
datastream.Hook("SetSequenceAssignCamera","SetSequenceAssignCamera", SetSequenceAssignCamera, nil);


/*************************************************
 * Recieves a message from the client which contains
 * the animation data in a 'waypoint'
 *************************************************/		
function SetWaypointParameters(player, data)

	if data != nil then
		local waypointEntity = ents.GetByIndex(data.entityIndex)
		if waypointEntity and waypointEntity:IsValid() then

			waypointEntity:UpdateAnimationData(data.animationSequence, data.transitionAnimation)
	
			local rootWaypoint = GetRootNode(waypointEntity)	
			if rootWaypoint and rootWaypoint:IsValid() then

				local ownedActors = {}
				for aeik, aeii in pairs(data.ownedActors) do
					table.insert(ownedActors, ents.GetByIndex(aeii))
				end

				rootWaypoint:UpdateActors(ownedActors)
				rootWaypoint:SetPlayState(data.playState)

			end			
		end
	end
end
datastream.Hook("SetWaypointParameters","SetWaypointParameters", SetWaypointParameters, nil);

//****************************************************
//*	Synchonizes the list of actor sequences from client
//* to server
function AnimatedCamera_SetActorSequences(player, data)

	print("recienved set actor sequences message")
	if(data) then
		
		print("data ok")
		local animatedCamera = ents.GetByIndex(data.EntIndex)
		if not(animatedCamera and animatedCamera:IsValid()) then
			return
		end
		print("data entity valid, seting actor sequences")
		animatedCamera:SetActorSequences(data.ActorSequences)
	end

end
datastream.Hook("AnimatedCamera_SetActorSequences", "AnimatedCamera_SetActorSequences", AnimatedCamera_SetActorSequences);

//****************************************************
//*	Synchonizes the list of actor sequences from client
//* to server
function AnimatedCamera_SetActorSequenceStates(player, data)

	if(data) then
		if data.EntIndexs then
			for Key, EntIndex in pairs(data.EntIndexs) do

				local sequenceEntity = ents.GetByIndex(EntIndex)
				if sequenceEntity and sequenceEntity:IsValid() then
					sequenceEntity:SetPlayState(data.PlayState)
				end
			end
		end
	end

end
datastream.Hook("AnimatedCamera_SetActorSequenceStates", "AnimatedCamera_SetActorSequenceStates", AnimatedCamera_SetActorSequenceStates);

end

if CLIENT then


	function AnimatedCamera_AssignSequence(data)

		print("Got assign sequence message") 
		if data then

			print("message data ok") 

			local animatedCamera = ents.GetByIndex(data.RecipientEntIdx)
			local sequenceEntity = ents.GetByIndex(data.SequenceEntIdx)

			if animatedCamera and animatedCamera:IsValid() and sequenceEntity and sequenceEntity:IsValid() then
				animatedCamera:AssignActorSequence(sequenceEntity)
			end
		end
	end
	datastream.Hook("AnimatedCamera_AssignSequence","AnimatedCamera_AssignSequence", AnimatedCamera_AssignSequence, nil);


	function funcSyncCLSequenceActors(syncData)

		if syncData then
			local recipientEnt = ents.GetByIndex(syncData.RecipientEntIdx)
			if recipientEnt and recipientEnt:IsValid() then

				local newActorEnt = ents.GetByIndex(syncData.NewActorEntIdx)
				if newActorEnt and newActorEnt:IsValid() then

					for ak, ao in pairs(recipientEnt.OwnedActors) do
						if ao == newActorEnt then
							return
						end
					end

					table.insert(recipientEnt.OwnedActors, newActorEnt)
				end
			end
		end
	end
	datastream.Hook("SyncCLSequenceActors","SyncCLSequenceActors", funcSyncCLSequenceActors, nil);

end